﻿#region Header
// Copyright 2007-2011, Jerónimo Milea
// 
// This file is part of NetJsWire.
// 
//     NetJsWire is free software: you can redistribute it and/or modify
//     it under the terms of the GNU General Public License as published by
//     the Free Software Foundation, either version 3 of the License, or
//     (at your option) any later version.
// 
//     NetJsWire is distributed in the hope that it will be useful,
//     but WITHOUT ANY WARRANTY; without even the implied warranty of
//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//     GNU General Public License for more details.
// 
//     You should have received a copy of the GNU General Public License
//     along with NetJsWire.  If not, see <http://www.gnu.org/licenses/>.
#endregion

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Xml;
using NetJsWire.Widgets.Core;

namespace NetJsWire.JsonRpcHandler
{
    /// <summary>
    ///   The interface that all Renderers have to implement.
    /// </summary>
    [TypeConverter( typeof( ExpandableObjectConverter ) )]
    public interface IRenderer
    {
        /// <summary>
        ///   The Base object this Element represents, can be a Control or Component.
        /// </summary>
        dynamic Base { get; set; }

        /// <summary>
        ///   Is the Element rendered?
        /// </summary>
        bool Rendered { get; set; }

        ///<summary>
        ///  The client ID the object is going to have in Javascript.
        ///  This ID can be later referenced in Javascript code, the naming convention is pretty easy to follow, it goes like this:
        ///  NetJsWire.App.TopLevelContainer.AnyOtherContainer.YourObject, i.e.: if you have a Window named 'MyWindow' and the Window has a TextField named 'textField1'
        ///  then the ClientID will become: NetJsWire.App.MyWindow.textField1
        ///</summary>
        string ClientID { get; set; }

        ///<summary>
        ///  The internal ID of the element that identifies it in the application objects collection.
        ///  <remarks>
        ///    When this property is set manually the ClientId is set to the same value
        ///  </remarks>
        ///</summary>
        ///<exception cref = "NullReferenceException">Thrown if value is set to null.</exception>
        string InternalID { get; set; }

        /// <summary>
        ///   Returns a safe call to Ext.getCmp to return our component, useful if you dont have a client reference.
        /// </summary>
        string GetCmp { get; }

        /// <summary>
        ///   Returns the parent renderer name (or part, body in case of panels) this widget is going to be rendered into. (Deprecated)
        /// </summary>
        string ClientParentToRender { get; }

        /// <summary>
        ///   The name of the <see cref = "Base" /> object.
        /// </summary>
        string BaseName { get; }

        /// <summary>
        ///   Returns the parent of our base Widget.
        /// </summary>
        Component BaseParent { get; }

        /// <summary>
        ///   The XmlNode that widget belongs to.
        /// </summary>
        XmlNode ControlNode { get; set; }

        /// <summary>
        ///   True if this IRenderer its a <see cref = "ITopLevelContainer" />.
        ///   <remarks>
        ///     There are only 2 types of ITopLevelContainer so far: <see cref = "NetJsWire.Widgets.Ui.Window.Window">Window</see> and <see cref = "NetJsWire.Widgets.Core.ClientDocument">ClientDocument</see>.
        ///   </remarks>
        /// </summary>
        bool TopLevelContainer { get; }
        List<object> Plugins { get; set; }
        bool EventsAdded { get; set; }

        /// <summary>
        ///   Renders the element to generate the client code.
        /// </summary>
        void Render();

        /// <summary>
        ///   Sets a construction property for the client object.
        /// </summary>
        /// <param name = "name">Name of the property.</param>
        /// <param name = "value">Value of to initialize the property.</param>
        void SetConstructionProperty( string command, object value );

        /// <summary>
        ///   Removes a construction property from the list.
        /// </summary>
        /// <param name = "name">Name of the property.</param>
        void RemoveConstructionProperty( string name );

        ///<summary>
        ///  Calls a client command.
        ///  <example>
        ///    <code>
        ///      myControl.CallCommand("upTime", 100);
        ///      ...
        ///      ...
        ///    </code>
        ///    Translates into:
        ///    <code>
        ///      NetJsWire.App.myControl.upTime(100);
        ///    </code>
        ///    in client code.
        ///  </example>
        ///  <remarks>
        ///    This is a Dictionary so if you call this method several times the value gets replaced and the last one is executed.
        ///    This can be usefull for Events like ComboBox.SelectedIndexChanged that can occur several times before the combo gets 
        ///    rendered and this way we can be sure that only the last value set is passed to the client.
        ///  </remarks>
        ///</summary>
        ///<param name = "name">Command name.</param>
        ///<param name = "value">The value to pass to the command function.</param>
        void CallCommand( string name, object value );

        ///<summary>
        ///  Adds or changes a style property, this affects the style of the DOM object in client.
        ///</summary>
        ///<param name = "name">Name of the style property.</param>
        ///<param name = "value">Value of the style property.</param>
        void AddStyleProperty( string name, object value );

        ///<summary>
        ///  Sets a client property on the object.
        ///  <example>
        ///    <code>
        ///      myControl.SetEqualProperty("upTime", 100);
        ///    </code>
        ///    Translates into:
        ///    <code>
        ///      NetJsWire.App.myControl.upTime = 100;
        ///    </code>
        ///    in client code.
        ///  </example>
        ///</summary>
        ///<param name = "name">BlockRefresh name.</param>
        ///<param name = "value">The value to set the property to.</param>
        void SetEqualProperty( string name, object value );

        ///<summary>
        ///  Executes a client command.
        ///  <example>
        ///    <code>
        ///      myControl.AddCommand("upTime", 100);
        ///      ...
        ///      ...
        ///    </code>
        ///    Translates into:
        ///    <code>
        ///      NetJsWire.App.myControl.upTime(100);
        ///    </code>
        ///    in client code.
        ///  </example>
        ///  <remarks>
        ///    This is a FIFO Queue, you can call this method several times and the commands are going to be executed one after the other.
        ///  </remarks>
        ///</summary>
        ///<param name = "name">Command name.</param>
        ///<param name = "value">The value(s) to pass to the command function.</param>
        void AddCommand( string name, params object[] value );

        /// <summary>
        ///   Adds a direct command to the queue, this function is for passing arbitrary code to the client it works like this:
        ///   <example>
        ///     <code>
        ///       MyWidgetRenderer.AddDirectCommand("x = ", "SomeFunctionOrVar()");
        ///     </code>
        ///     Gest translated into:
        ///     <code>
        ///       x = SomeFunctionOrVar();
        ///     </code>
        ///   </example>
        ///   <remarks>
        ///     This method adds a semi colon (;) to the end of the statement, you dont need to add one.
        ///   </remarks>
        /// </summary>
        /// <param name = "command"></param>
        /// <param name = "value"></param>
        void AddDirectCommand( string command, object value );

        void AddEvent( string name, Delegate value );

        /// <summary>
        ///   Adds a command to be executed in Javascript, it can be a call to a function or a method.
        ///   <i>* This method prepends the Widget name its for calling functions or constructing objects.</i>
        /// </summary>
        /// <param name = "command">The name of the method or function to execute.</param>
        /// <param name = "value">The parameter to pass to the method.</param>
        void AddApplicationTailCommand( string command, object value );

        /// <summary>
        ///   Adds code that needs to be executed before this Widget is created, it can be any valid Javascript code.
        /// </summary>
        /// <param name = "command">The command to be executed.</param>
        /// <param name = "code">The code to be executed.</param>
        void AddPrecodeCommand( string command, string code );

        /// <summary>
        ///   Adds code that needs to be executed before this Widget is created, it can be any valid Javascript code.
        /// </summary>
        /// <param name = "precode">The code to be executed.</param>
        void AddPrecode( string command );

        /// <summary>
        ///   An equal command to be executed in Javascript, this is usefull if you need to set the value of a variable that doesnt belong to a Widget.
        ///   <remarks>
        ///     This method does not prepends the Widget name its for calling functios or constructing objects.
        ///   </remarks>
        ///   <example>
        ///     <code>
        ///       MyWidget.Renderer.AddApplicationTailDirectEqualCommand("MyJavascriptObjectOrVar", true);
        ///     </code>
        ///     Gets translated into:
        ///     <code>
        ///       MyJavascriptObjectOrVar = true;
        ///     </code>
        ///   </example>
        /// </summary>
        /// <param name = "objOrVar">The name of your Javascript object or variable.</param>
        /// <param name = "value">The new value of the Javascript object or variable.</param>
        void AddApplicationTailDirectEqualCommand( string command, object value );

        ///<summary>
        ///  This function adds code to be executed arbitrarily in Javascript, prepending the Widget client name (ClientID).
        ///  <example>
        ///    This code in server:
        ///    <code>
        ///      MyWidget.Renderer.AddRawDotCode( "CallMyFunction()" );
        ///    </code>
        ///    Gets translated into this Javascript code:
        ///    <code>
        ///      MyWidgetClientId.CallMyFunction();
        ///    </code>
        ///    <remarks>
        ///      This method appends a semicolon to the end of the statement (;).
        ///    </remarks>
        ///  </example>
        ///</summary>
        ///<param name = "code">The code to be executed</param>
        void AddRawDotCode( string code );

        /// <summary>
        ///   Add a client event to the Element in the form of: Element.on('name', function);
        /// </summary>
        /// <param name = "name">The event name.</param>
        /// <param name = "function">A function name or inline code to execute.</param>
        void AddClientEvent( string name, string function );

        void AddKeyNav( string keys, string function );

        event EventHandler AfterRender;

        void SetLayoutConfigProperty( string propName, object value );
        void RemoveLayoutConfigProperty( string propName );
        void SetAttribute( string name, object value );
    }
}